我们知道声明式事务是通过spring 的aop实现的,先看spring aop的实现

Spring aop

注解属性解析

spring能完成AOP的代理,因为Spring有这样的配置

<aop:aspectj-autoproxy />

这一配置使得整个Spring项目拥有了AOP的功能.那么spring如何解析aop配置的呢?

根据spring 代码习惯,命名空间的解析都在相应的jar下的config包里,取名xxNamespaceHandler.比如aop在Spring-aop.jar中org.springframework.aop.config包内有AopNamespaceHandler.

@Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

可以看到当指定了aspectj-autoproxy,会使用org.springframework.aop.config.AspectJAutoProxyBeanDefinitionParser解析元素.AspectJAutoProxyBeanDefinitionParser的parse方法调用的是AopNamespaceUtils类中的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,作用是初始化一个AOP专用的Bean,并且注册到Spring容器中。

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
           ParserContext parserContext, Element sourceElement) {
       BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
               parserContext.getRegistry(), parserContext.extractSource(sourceElement));
       useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
       registerComponentIfNecessary(beanDefinition, parserContext);
   }

3句对应三个操作

a.注册一个AnnotationAwareAspectJAutoProxyCreator(称它为自动代理器),Creator是AOP的操作核心,也是扫描Bean,代理Bean的操作所在。

b.解析配置元素,决定代理的模式。包含有JDK动态代理,CGLIB代理

c.作为系统组件,把Creator放到Spring容器中。让Spring实例化,启动这个Creator。

重点看下第2句,后面会用到

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
        if (sourceElement != null) {
      //public static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
            boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
      //private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";
            boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

不难发现其实就是解析配置,设置属性的过程

jdk or cglib选取

org.springframework.aop.framework.DefaultAopProxyFactory

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //optimize:通过cglib控制的代理使用优化策略,default=false
    //proxyTargetClass:设置直接通过目标类来代理,而不是接口,default=false.
    //hasNoUserSuppliedProxyInterfaces:是否实现了接口,是-else
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
      //如果代理对象是Interface类型,仍然使用jdk代理
      //或者,当代理目标是getProxyClass方法或者newProxyInstance方法生成时,仍然使用jdk代理
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
      //默认情况Optimize与proxyTargetClass=false,实现了接口时hasNoUserSuppliedProxyInterfaces=false,使用jdk代理
            return new JdkDynamicAopProxy(config);
        }
    }

    /**
     * Determine whether the supplied {@link AdvisedSupport} has only the
     * {@link org.springframework.aop.SpringProxy} interface specified
     * (or no proxy interfaces specified at all).
     */
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
    //没有实现接口,或者类只是SpringProxy.class的子类。
    //isAssignableFrom方法用于判断两个类或者接口是否是相同的类
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }

}

从源码看出,使用cglib有3个条件判断,config.isOptimize()、config.isProxyTargetClass()和hasNoUserSuppliedProxyInterfaces(config)。其中config.isOptimize()与config.isProxyTargetClass()默认返回是false,因此默认情况下就由hasNoUserSuppliedProxyInterfaces(config)的结果决定,hasNoUserSuppliedProxyInterfaces(config)是在判断代理的对象是否有实现接口,有实现接口的话直接走new JdkDynamicAopProxy(config)分支,即使用JDK的动态代理。

ProxyTargetClass通过配置决定,Optimize可以通过bean属性指定.



JDK与CGlib方式实现aop总结

Spring会自动在JDK动态代理和CGLIB之间转换,选取合适的代理方式,规则如下:

1.如果目标对象实现了接口,默认情况采用jdk动态代理实现aop,所有由目标对象实现的接口将全部被代理。

2.如果目标对象实现了接口,可以强制指定使用cglib实现aop,方式为配置<aop:aspectj-autoproxy proxy-target-class=”true”/>,且需引入cglib的Jar,如果已经有spring-core的jar包,则无需引入,因为spring-core中包含了cglib。

3.如果对象没有实现接口,就使用cglib方式

JDK动态代理与CGlib字节码生成的区别

JDK动态代理,必须是实现了接口的类生成代理,实现方式是运行时创建一个接口的实现类.JDK代理通过这些接口获取构造方法,用这个构造方法和InvocationHandler,实例化一个对象出来。所以JDK的方式是基于接口的。

CGlib是针对类生成代理,用目标类生成一个子类,子类重写父类的方法,达到动态代理的效果,因此,不能用于声明为final的方法或类上.底层依赖ASM操作字节码,性能比JDK好

实现类中方法自我调用的代理

属性expose-proxy=true,可以对目标对象的自我调用进行增强,然后按如下方式改写代码

<aop:aspectj-autoproxy expose-proxy="true"/>

改写代码

this.hello()
改为
((HelloService) AopContext.currentProxy()).hello()

留言

2018-05-01